1 /*******************************************************************************
\r
2 * Tracealyzer v2.4.1 Recorder Library
\r
3 * Percepio AB, www.percepio.com
\r
7 * Functions used by trcKernelHooks.h.
\r
10 * This software is copyright Percepio AB. The recorder library is free for
\r
11 * use together with Percepio products. You may distribute the recorder library
\r
12 * in its original form, including modifications in trcHardwarePort.c/.h
\r
13 * given that these modification are clearly marked as your own modifications
\r
14 * and documented in the initial comment section of these source files.
\r
15 * This software is the intellectual property of Percepio AB and may not be
\r
16 * sold or in other ways commercially redistributed without explicit written
\r
17 * permission by Percepio AB.
\r
20 * The trace tool and recorder library is being delivered to you AS IS and
\r
21 * Percepio AB makes no warranty as to its use or performance. Percepio AB does
\r
22 * not and cannot warrant the performance or results you may obtain by using the
\r
23 * software or documentation. Percepio AB make no warranties, express or
\r
24 * implied, as to noninfringement of third party rights, merchantability, or
\r
25 * fitness for any particular purpose. In no event will Percepio AB, its
\r
26 * technology partners, or distributors be liable to you for any consequential,
\r
27 * incidental or special damages, including any lost profits or lost savings,
\r
28 * even if a representative of Percepio AB has been advised of the possibility
\r
29 * of such damages, or for any claim by any third party. Some jurisdictions do
\r
30 * not allow the exclusion or limitation of incidental, consequential or special
\r
31 * damages, or the exclusion of implied warranties or limitations on how long an
\r
32 * implied warranty may last, so the above limitations may not apply to you.
\r
34 * Copyright Percepio AB, 2013.
\r
36 ******************************************************************************/
\r
38 #include "trcKernel.h"
\r
40 #if (USE_TRACEALYZER_RECORDER == 1)
\r
44 /* Internal variables */
\r
45 uint8_t nISRactive = 0;
\r
46 objectHandleType handle_of_last_logged_task = 0;
\r
47 uint8_t inExcludedTask = 0;
\r
49 static uint32_t prvTraceGetParam(uint32_t, uint32_t);
\r
51 #if !defined INCLUDE_READY_EVENTS || INCLUDE_READY_EVENTS == 1
\r
52 /*******************************************************************************
\r
53 * vTraceStoreTaskReady
\r
55 * This function stores a ready state for the task handle sent in as parameter.
\r
56 ******************************************************************************/
\r
57 void vTraceStoreTaskReady(objectHandleType handle)
\r
62 TRACE_ASSERT(handle > 0 && handle <= NTask, "vTraceStoreTaskReady: Invalid value for handle", );
\r
66 /***********************************************************************
\r
67 * This should never occur, as the tick- and kernel call ISR is on lowest
\r
68 * interrupt priority and always are disabled during the critical sections
\r
70 ***********************************************************************/
\r
72 vTraceError("Recorder busy - high priority ISR using syscall? (1)");
\r
76 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
\r
78 if (!TRACE_GET_TASK_FLAG_ISEXCLUDED(handle))
\r
80 dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);
\r
81 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
\r
83 tr = (TREvent*)xTraceNextFreeEventBufferSlot();
\r
87 tr->type = DIV_TASK_READY;
\r
89 tr->objHandle = handle;
\r
91 prvTraceUpdateCounters();
\r
99 /*******************************************************************************
\r
100 * vTraceStoreKernelCall
\r
102 * This is the main integration point for storing kernel calls, and
\r
103 * is called by the hooks in trcKernelHooks.h (see trcKernelPort.h for event codes).
\r
104 ******************************************************************************/
\r
105 void vTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_t objectNumber)
\r
110 TRACE_ASSERT(ecode < 0xFF, "vTraceStoreKernelCall: ecode >= 0xFF", );
\r
111 TRACE_ASSERT(objectClass < TRACE_NCLASSES, "vTraceStoreKernelCall: objectClass >= TRACE_NCLASSES", );
\r
112 TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "vTraceStoreKernelCall: Invalid value for objectNumber", );
\r
116 /*************************************************************************
\r
117 * This may occur if a high-priority ISR is illegally using a system call,
\r
118 * or creates a user event.
\r
119 * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls
\r
120 * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY).
\r
121 *************************************************************************/
\r
123 vTraceError("Recorder busy - high priority ISR using syscall? (2)");
\r
127 if (handle_of_last_logged_task == 0)
\r
132 if (RecorderDataPtr->recorderActive)
\r
135 /* If it is an ISR or NOT an excluded task, this kernel call will be stored in the trace */
\r
136 if (nISRactive || !inExcludedTask)
\r
138 /* Check if the referenced object or the event code is excluded */
\r
139 if (!uiTraceIsObjectExcluded(objectClass, objectNumber) && !TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(ecode))
\r
141 trcCRITICAL_SECTION_BEGIN();
\r
142 dts1 = (uint16_t)prvTraceGetDTS(0xFFFF);
\r
144 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
\r
146 kse = (KernelCall*) xTraceNextFreeEventBufferSlot();
\r
150 kse->type = (uint8_t)ecode;
\r
151 kse->objHandle = (uint8_t)objectNumber;
\r
152 prvTraceUpdateCounters();
\r
155 trcCRITICAL_SECTION_END();
\r
161 /*******************************************************************************
\r
162 * vTraceStoreKernelCallWithParam
\r
164 * Used for storing kernel calls with a handle and a numeric parameter. This is
\r
165 * only used for traceTASK_PRIORITY_SET at the moment.
\r
166 ******************************************************************************/
\r
167 void vTraceStoreKernelCallWithParam(uint32_t evtcode,
\r
168 traceObjectClass objectClass,
\r
169 uint32_t objectNumber,
\r
172 KernelCallWithParamAndHandle * kse;
\r
175 TRACE_ASSERT(evtcode < 0xFF, "vTraceStoreKernelCall: evtcode >= 0xFF", );
\r
176 TRACE_ASSERT(objectClass < TRACE_NCLASSES, "vTraceStoreKernelCallWithParam: objectClass >= TRACE_NCLASSES", );
\r
177 TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "vTraceStoreKernelCallWithParam: Invalid value for objectNumber", );
\r
179 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task &&
\r
180 (! inExcludedTask || nISRactive))
\r
184 /*************************************************************************
\r
185 * This may occur if a high-priority ISR is illegally using a system call,
\r
186 * or creates a user event.
\r
187 * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls
\r
188 * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY).
\r
189 *************************************************************************/
\r
191 vTraceError("Recorder busy - high priority ISR using syscall? (3)");
\r
195 /* Check if the referenced object or the event code is excluded */
\r
196 if (!uiTraceIsObjectExcluded(objectClass, objectNumber) && !TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode))
\r
198 trcCRITICAL_SECTION_BEGIN();
\r
199 dts2 = (uint8_t)prvTraceGetDTS(0xFF);
\r
201 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
\r
203 kse = (KernelCallWithParamAndHandle*) xTraceNextFreeEventBufferSlot();
\r
207 kse->type = (uint8_t)evtcode;
\r
208 kse->objHandle = (uint8_t)objectNumber;
\r
209 kse->param = param;
\r
210 prvTraceUpdateCounters();
\r
213 trcCRITICAL_SECTION_END();
\r
218 /*******************************************************************************
\r
221 * Used for storing extra bytes for kernel calls with numeric parameters.
\r
222 ******************************************************************************/
\r
223 static uint32_t prvTraceGetParam(uint32_t param_max, uint32_t param)
\r
227 TRACE_ASSERT(param_max == 0xFF || param_max == 0xFFFF, "prvTraceGetParam: Invalid value for param_max", param);
\r
229 if (param <= param_max)
\r
235 xps = (XPSEvent*) xTraceNextFreeEventBufferSlot();
\r
238 xps->type = DIV_XPS;
\r
239 xps->xps_8 = (param & (0xFF00 & ~param_max)) >> 8;
\r
240 xps->xps_16 = (param & (0xFFFF0000 & ~param_max)) >> 16;
\r
241 prvTraceUpdateCounters();
\r
244 return param & param_max;
\r
248 /*******************************************************************************
\r
249 * vTraceStoreKernelCallWithNumericParamOnly
\r
251 * Used for storing kernel calls with numeric parameters only. This is
\r
252 * only used for traceTASK_DELAY and traceDELAY_UNTIL at the moment.
\r
253 ******************************************************************************/
\r
254 void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param)
\r
256 KernelCallWithParam16 * kse;
\r
258 uint16_t restParam = 0;
\r
260 TRACE_ASSERT(evtcode < 0xFF, "vTraceStoreKernelCallWithNumericParamOnly: Invalid value for evtcode", );
\r
262 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task
\r
263 && (! inExcludedTask || nISRactive))
\r
265 /* Check if the event code is excluded */
\r
266 if (!TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode))
\r
270 /*************************************************************************
\r
271 * This may occur if a high-priority ISR is illegally using a system call,
\r
272 * or creates a user event.
\r
273 * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls
\r
274 * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY).
\r
275 *************************************************************************/
\r
277 vTraceError("Recorder busy - high priority ISR using syscall? (4)");
\r
281 trcCRITICAL_SECTION_BEGIN();
\r
282 dts6 = (uint8_t)prvTraceGetDTS(0xFF);
\r
284 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
\r
286 restParam = (uint16_t)prvTraceGetParam(0xFFFF, param);
\r
288 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
\r
290 kse = (KernelCallWithParam16*) xTraceNextFreeEventBufferSlot();
\r
294 kse->type = (uint8_t)evtcode;
\r
295 kse->param = restParam;
\r
296 prvTraceUpdateCounters();
\r
300 trcCRITICAL_SECTION_END();
\r
305 /*******************************************************************************
\r
306 * vTraceStoreTaskswitch
\r
307 * Called by the scheduler from the SWITCHED_OUT hook, and by uiTraceStart.
\r
308 * At this point interrupts are assumed to be disabled!
\r
309 ******************************************************************************/
\r
310 void vTraceStoreTaskswitch(objectHandleType task_handle)
\r
314 int8_t skipEvent = 0;
\r
316 TRACE_ASSERT(task_handle <= NTask, "vTraceStoreTaskswitch: Invalid value for task_handle", );
\r
318 /***************************************************************************
\r
319 This is used to detect if a high-priority ISRs is illegally using the
\r
320 recorder ISR trace functions (vTraceStoreISRBegin and ...End) while the
\r
321 recorder is busy with a task-level event or lower priority ISR event.
\r
323 If this is detected, it triggers a call to vTraceError with the error
\r
324 "Illegal call to vTraceStoreISRBegin/End". If you get this error, it means
\r
325 that the macro trcCRITICAL_SECTION_BEGIN does not disable this ISR, as required.
\r
327 Note: Setting recorder_busy is normally handled in our macros
\r
328 trcCRITICAL_SECTION_BEGIN and _END, but is needed explicitly in this
\r
329 function since critical sections should not be used in the context switch
\r
331 ***************************************************************************/
\r
334 /* Skip the event if the task has been excluded, using vTraceExcludeTask */
\r
335 if (TRACE_GET_TASK_FLAG_ISEXCLUDED(task_handle))
\r
338 inExcludedTask = 1;
\r
342 inExcludedTask = 0;
\r
345 /* Skip the event if the same task is scheduled */
\r
346 if (task_handle == handle_of_last_logged_task)
\r
352 if (!RecorderDataPtr->recorderActive)
\r
357 /* If this event should be logged, log it! */
\r
358 if (skipEvent == 0)
\r
360 dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);
\r
362 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
\r
364 handle_of_last_logged_task = task_handle;
\r
365 ts = (TSEvent*)xTraceNextFreeEventBufferSlot();
\r
369 if (uiTraceGetObjectState(TRACE_CLASS_TASK,
\r
370 handle_of_last_logged_task) == TASK_STATE_INSTANCE_ACTIVE)
\r
372 ts->type = TS_TASK_RESUME;
\r
376 ts->type = TS_TASK_BEGIN;
\r
380 ts->objHandle = handle_of_last_logged_task;
\r
382 vTraceSetObjectState(TRACE_CLASS_TASK,
\r
383 handle_of_last_logged_task,
\r
384 TASK_STATE_INSTANCE_ACTIVE);
\r
386 prvTraceUpdateCounters();
\r
391 /* See comment on recorder_busy++ above. */
\r
395 /*******************************************************************************
\r
396 * vTraceStoreNameCloseEvent
\r
398 * Updates the symbol table with the name of this object from the dynamic
\r
399 * objects table and stores a "close" event, holding the mapping between handle
\r
400 * and name (a symbol table handle). The stored name-handle mapping is thus the
\r
401 * "old" one, valid up until this point.
\r
402 ******************************************************************************/
\r
403 #if (INCLUDE_OBJECT_DELETE == 1)
\r
404 void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle,
\r
405 traceObjectClass objectclass)
\r
407 ObjCloseNameEvent * ce;
\r
411 TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceStoreObjectNameOnCloseEvent: objectclass >= TRACE_NCLASSES", );
\r
412 TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceStoreObjectNameOnCloseEvent: Invalid value for handle", );
\r
414 if (RecorderDataPtr->recorderActive)
\r
416 name = TRACE_PROPERTY_NAME_GET(objectclass, handle);
\r
418 idx = prvTraceOpenSymbol(name, 0);
\r
420 // Interrupt disable not necessary, already done in trcHooks.h macro
\r
421 ce = (ObjCloseNameEvent*) xTraceNextFreeEventBufferSlot();
\r
424 ce->type = EVENTGROUP_OBJCLOSE_NAME + objectclass;
\r
425 ce->objHandle = handle;
\r
426 ce->symbolIndex = idx;
\r
427 prvTraceUpdateCounters();
\r
432 void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle,
\r
433 traceObjectClass objectclass)
\r
435 ObjClosePropEvent * pe;
\r
437 TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceStoreObjectPropertiesOnCloseEvent: objectclass >= TRACE_NCLASSES", );
\r
438 TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceStoreObjectPropertiesOnCloseEvent: Invalid value for handle", );
\r
440 if (RecorderDataPtr->recorderActive)
\r
442 // Interrupt disable not necessary, already done in trcHooks.h macro
\r
443 pe = (ObjClosePropEvent*) xTraceNextFreeEventBufferSlot();
\r
446 if (objectclass == TRACE_CLASS_TASK)
\r
448 pe->arg1 = TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, handle);
\r
449 pe->arg2 = 0; // Legacy - IFE info removed.
\r
450 pe->arg3 = 0; // Legacy - IFE info removed.
\r
452 pe->arg1 = TRACE_PROPERTY_OBJECT_STATE(objectclass, handle);
\r
454 pe->type = EVENTGROUP_OBJCLOSE_PROP + objectclass;
\r
455 prvTraceUpdateCounters();
\r
461 void vTraceSetPriorityProperty(uint8_t objectclass, uint8_t id, uint8_t value)
\r
463 TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceSetPriorityProperty: objectclass >= TRACE_NCLASSES", );
\r
464 TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceSetPriorityProperty: Invalid value for id", );
\r
466 TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id) = value;
\r
469 uint8_t uiTraceGetPriorityProperty(uint8_t objectclass, uint8_t id)
\r
471 TRACE_ASSERT(objectclass < TRACE_NCLASSES, "uiTraceGetPriorityProperty: objectclass >= TRACE_NCLASSES", 0);
\r
472 TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiTraceGetPriorityProperty: Invalid value for id", 0);
\r
474 return TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id);
\r
477 void vTraceSetObjectState(uint8_t objectclass, uint8_t id, uint8_t value)
\r
479 TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceSetObjectState: objectclass >= TRACE_NCLASSES", );
\r
480 TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceSetObjectState: Invalid value for id", );
\r
482 TRACE_PROPERTY_OBJECT_STATE(objectclass, id) = value;
\r
485 uint8_t uiTraceGetObjectState(uint8_t objectclass, uint8_t id)
\r
487 TRACE_ASSERT(objectclass < TRACE_NCLASSES, "uiTraceGetObjectState: objectclass >= TRACE_NCLASSES", 0);
\r
488 TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiTraceGetObjectState: Invalid value for id", 0);
\r
490 return TRACE_PROPERTY_OBJECT_STATE(objectclass, id);
\r
493 void vTraceSetTaskInstanceFinished(objectHandleType handle)
\r
495 TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_TASK], "vTraceSetTaskInstanceFinished: Invalid value for handle", );
\r
497 #if (USE_IMPLICIT_IFE_RULES == 1)
\r
498 TRACE_PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle) = 0;
\r