1 /*******************************************************************************
\r
2 * Trace Recorder Library for Tracealyzer v4.1.5
\r
3 * Percepio AB, www.percepio.com
\r
7 * The FreeRTOS-specific parts of the trace recorder
\r
10 * This file is part of the trace recorder library (RECORDER), which is the
\r
11 * intellectual property of Percepio AB (PERCEPIO) and provided under a
\r
12 * license as follows.
\r
13 * The RECORDER may be used free of charge for the purpose of recording data
\r
14 * intended for analysis in PERCEPIO products. It may not be used or modified
\r
15 * for other purposes without explicit permission from PERCEPIO.
\r
16 * You may distribute the RECORDER in its original source code form, assuming
\r
17 * this text (terms of use, disclaimer, copyright notice) is unchanged. You are
\r
18 * allowed to distribute the RECORDER with minor modifications intended for
\r
19 * configuration or porting of the RECORDER, e.g., to allow using it on a
\r
20 * specific processor, processor family or with a specific communication
\r
21 * interface. Any such modifications should be documented directly below
\r
22 * this comment block.
\r
25 * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty
\r
26 * as to its use or performance. PERCEPIO does not and cannot warrant the
\r
27 * performance or results you may obtain by using the RECORDER or documentation.
\r
28 * PERCEPIO make no warranties, express or implied, as to noninfringement of
\r
29 * third party rights, merchantability, or fitness for any particular purpose.
\r
30 * In no event will PERCEPIO, its technology partners, or distributors be liable
\r
31 * to you for any consequential, incidental or special damages, including any
\r
32 * lost profits or lost savings, even if a representative of PERCEPIO has been
\r
33 * advised of the possibility of such damages, or for any claim by any third
\r
34 * party. Some jurisdictions do not allow the exclusion or limitation of
\r
35 * incidental, consequential or special damages, or the exclusion of implied
\r
36 * warranties or limitations on how long an implied warranty may last, so the
\r
37 * above limitations may not apply to you.
\r
39 * Tabs are used for indent in this file (1 tab = 4 spaces)
\r
41 * Copyright Percepio AB, 2018.
\r
43 ******************************************************************************/
\r
45 #include "FreeRTOS.h"
\r
47 #if (!defined(TRC_USE_TRACEALYZER_RECORDER) && configUSE_TRACE_FACILITY == 1)
\r
48 #error Trace Recorder: You need to include trcRecorder.h at the end of your FreeRTOSConfig.h!
\r
51 #if (defined(TRC_USE_TRACEALYZER_RECORDER) && TRC_USE_TRACEALYZER_RECORDER == 1)
\r
53 #ifndef TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS
\r
54 /* TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS is missing in trcConfig.h. */
\r
55 #error "TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS must be defined in trcConfig.h."
\r
58 #ifndef TRC_CFG_INCLUDE_TIMER_EVENTS
\r
59 /* TRC_CFG_INCLUDE_TIMER_EVENTS is missing in trcConfig.h. */
\r
60 #error "TRC_CFG_INCLUDE_TIMER_EVENTS must be defined in trcConfig.h."
\r
63 #ifndef TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS
\r
64 /* TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS is missing in trcConfig.h. */
\r
65 #error "TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS must be defined in trcConfig.h."
\r
68 #ifndef TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS
\r
69 /* TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS is missing in trcConfig.h. Define this as 1 if using FreeRTOS v10 or later and like to trace stream buffer or message buffer events, otherwise 0. */
\r
70 #error "TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS must be defined in trcConfig.h."
\r
73 #if (configUSE_TICKLESS_IDLE != 0 && (TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR))
\r
75 The below error message is to alert you on the following issue:
\r
77 The hardware port selected in trcConfig.h uses the operating system timer for the
\r
78 timestamping, i.e., the periodic interrupt timer that drives the OS tick interrupt.
\r
80 When using "tickless idle" mode, the recorder needs an independent time source in
\r
81 order to correctly record the durations of the idle times. Otherwise, the trace may appear
\r
82 to have a different length than in reality, and the reported CPU load is also affected.
\r
84 You may override this warning by defining the TRC_CFG_ACKNOWLEDGE_TICKLESS_IDLE_WARNING
\r
85 macro in your trcConfig.h file. But then the time scale may be incorrect during
\r
86 tickless idle periods.
\r
88 To get this correct, override the default timestamping by setting TRC_CFG_HARDWARE_PORT
\r
89 in trcConfig.h to TRC_HARDWARE_PORT_APPLICATION_DEFINED and define the HWTC macros
\r
90 accordingly, using a free running counter or an independent periodic interrupt timer.
\r
91 See trcHardwarePort.h for details.
\r
93 For ARM Cortex-M3, M4 and M7 MCUs this is not an issue, since the recorder uses the
\r
94 DWT cycle counter for timestamping in these cases.
\r
97 #ifndef TRC_CFG_ACKNOWLEDGE_TICKLESS_IDLE_WARNING
\r
98 #error Trace Recorder: This timestamping mode is not recommended with Tickless Idle.
\r
100 #endif /* (configUSE_TICKLESS_IDLE != 0 && (TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)) */
\r
105 #if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X)
\r
106 /* If the project does not include the FreeRTOS timers, TRC_CFG_INCLUDE_TIMER_EVENTS must be set to 0 */
\r
107 #include "timers.h"
\r
108 #endif /* (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */
\r
110 #if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X)
\r
111 /* If the project does not include the FreeRTOS event groups, TRC_CFG_INCLUDE_TIMER_EVENTS must be set to 0 */
\r
112 #include "event_groups.h"
\r
113 #endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */
\r
115 #if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0)
\r
116 /* If the project does not include the FreeRTOS stream buffers, TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS must be set to 0 */
\r
117 #include "stream_buffer.h"
\r
118 #endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */
\r
120 uint32_t prvTraceGetQueueNumber(void* handle);
\r
122 #if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_8_X)
\r
124 extern unsigned char ucQueueGetQueueNumber( xQueueHandle pxQueue );
\r
125 extern void vQueueSetQueueNumber( xQueueHandle pxQueue, unsigned char ucQueueNumber );
\r
126 extern unsigned char ucQueueGetQueueType( xQueueHandle pxQueue );
\r
128 uint32_t prvTraceGetQueueNumber(void* handle)
\r
130 return (uint32_t)ucQueueGetQueueNumber(handle);
\r
133 uint32_t prvTraceGetQueueNumber(void* handle)
\r
135 return (uint32_t)uxQueueGetQueueNumber(handle);
\r
137 #endif /* (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_8_X) */
\r
139 uint8_t prvTraceGetQueueType(void* handle)
\r
141 // This is either declared in header file in FreeRTOS 8 and later, or as extern above
\r
142 return ucQueueGetQueueType(handle);
\r
146 uint16_t prvTraceGetTaskNumberLow16(void* handle)
\r
148 return TRACE_GET_LOW16(uxTaskGetTaskNumber(handle));
\r
151 uint16_t prvTraceGetTaskNumberHigh16(void* handle)
\r
153 return TRACE_GET_HIGH16(uxTaskGetTaskNumber(handle));
\r
156 void prvTraceSetTaskNumberLow16(void* handle, uint16_t value)
\r
158 vTaskSetTaskNumber(handle, TRACE_SET_LOW16(uxTaskGetTaskNumber(handle), value));
\r
161 void prvTraceSetTaskNumberHigh16(void* handle, uint16_t value)
\r
163 vTaskSetTaskNumber(handle, TRACE_SET_HIGH16(uxTaskGetTaskNumber(handle), value));
\r
166 uint16_t prvTraceGetQueueNumberLow16(void* handle)
\r
168 return TRACE_GET_LOW16(prvTraceGetQueueNumber(handle));
\r
171 uint16_t prvTraceGetQueueNumberHigh16(void* handle)
\r
173 return TRACE_GET_HIGH16(prvTraceGetQueueNumber(handle));
\r
176 void prvTraceSetQueueNumberLow16(void* handle, uint16_t value)
\r
178 vQueueSetQueueNumber(handle, TRACE_SET_LOW16(prvTraceGetQueueNumber(handle), value));
\r
181 void prvTraceSetQueueNumberHigh16(void* handle, uint16_t value)
\r
183 vQueueSetQueueNumber(handle, TRACE_SET_HIGH16(prvTraceGetQueueNumber(handle), value));
\r
186 #if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0)
\r
188 uint16_t prvTraceGetTimerNumberLow16(void* handle)
\r
190 return TRACE_GET_LOW16(uxTimerGetTimerNumber(handle));
\r
193 uint16_t prvTraceGetTimerNumberHigh16(void* handle)
\r
195 return TRACE_GET_HIGH16(uxTimerGetTimerNumber(handle));
\r
198 void prvTraceSetTimerNumberLow16(void* handle, uint16_t value)
\r
200 vTimerSetTimerNumber(handle, TRACE_SET_LOW16(uxTimerGetTimerNumber(handle), value));
\r
203 void prvTraceSetTimerNumberHigh16(void* handle, uint16_t value)
\r
205 vTimerSetTimerNumber(handle, TRACE_SET_HIGH16(uxTimerGetTimerNumber(handle), value));
\r
207 #endif /* (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */
\r
209 #if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0)
\r
211 uint16_t prvTraceGetEventGroupNumberLow16(void* handle)
\r
213 return TRACE_GET_LOW16(uxEventGroupGetNumber(handle));
\r
216 uint16_t prvTraceGetEventGroupNumberHigh16(void* handle)
\r
218 return TRACE_GET_HIGH16(uxEventGroupGetNumber(handle));
\r
221 void prvTraceSetEventGroupNumberLow16(void* handle, uint16_t value)
\r
223 vEventGroupSetNumber(handle, TRACE_SET_LOW16(uxEventGroupGetNumber(handle), value));
\r
226 void prvTraceSetEventGroupNumberHigh16(void* handle, uint16_t value)
\r
228 vEventGroupSetNumber(handle, TRACE_SET_HIGH16(uxEventGroupGetNumber(handle), value));
\r
230 #endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */
\r
232 #if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0)
\r
234 uint16_t prvTraceGetStreamBufferNumberLow16(void* handle)
\r
236 return TRACE_GET_LOW16(uxStreamBufferGetStreamBufferNumber(handle));
\r
239 uint16_t prvTraceGetStreamBufferNumberHigh16(void* handle)
\r
241 return TRACE_GET_HIGH16(uxStreamBufferGetStreamBufferNumber(handle));
\r
244 void prvTraceSetStreamBufferNumberLow16(void* handle, uint16_t value)
\r
246 vStreamBufferSetStreamBufferNumber(handle, TRACE_SET_LOW16(uxStreamBufferGetStreamBufferNumber(handle), value));
\r
249 void prvTraceSetStreamBufferNumberHigh16(void* handle, uint16_t value)
\r
251 vStreamBufferSetStreamBufferNumber(handle, TRACE_SET_HIGH16(uxStreamBufferGetStreamBufferNumber(handle), value));
\r
253 #endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */
\r
255 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
\r
257 static void* pCurrentTCB = NULL;
\r
258 #if (defined(configENABLE_BACKWARD_COMPATIBILITY) && configENABLE_BACKWARD_COMPATIBILITY == 0)
\r
259 /* We're explicitly not using compatibility mode */
\r
260 static TaskHandle_t HandleTzCtrl = NULL; /* TzCtrl task TCB */
\r
262 /* We're using compatibility mode, or we're running an old kernel */
\r
263 static xTaskHandle HandleTzCtrl = NULL; /* TzCtrl task TCB */
\r
266 #if defined(configSUPPORT_STATIC_ALLOCATION)
\r
267 #if (configSUPPORT_STATIC_ALLOCATION == 1)
\r
268 static StackType_t stackTzCtrl[TRC_CFG_CTRL_TASK_STACK_SIZE];
\r
269 static StaticTask_t tcbTzCtrl;
\r
273 /* Monitored by TzCtrl task, that give warnings as User Events */
\r
274 extern volatile uint32_t NoRoomForSymbol;
\r
275 extern volatile uint32_t NoRoomForObjectData;
\r
276 extern volatile uint32_t LongestSymbolName;
\r
277 extern volatile uint32_t MaxBytesTruncated;
\r
279 /* Keeps track of previous values, to only react on changes. */
\r
280 static uint32_t NoRoomForSymbol_last = 0;
\r
281 static uint32_t NoRoomForObjectData_last = 0;
\r
282 static uint32_t LongestSymbolName_last = 0;
\r
283 static uint32_t MaxBytesTruncated_last = 0;
\r
285 /* User Event Channel for giving warnings regarding NoRoomForSymbol etc. */
\r
286 traceString trcWarningChannel;
\r
288 #define TRC_PORT_MALLOC(size) pvPortMalloc(size)
\r
290 TRC_STREAM_PORT_ALLOCATE_FIELDS()
\r
292 /* Called by TzCtrl task periodically (Normally every 100 ms) */
\r
293 static void prvCheckRecorderStatus(void);
\r
295 extern void prvTraceWarning(int errCode);
\r
297 /* The TzCtrl task - receives commands from Tracealyzer (start/stop) */
\r
298 static portTASK_FUNCTION( TzCtrl, pvParameters );
\r
300 /*******************************************************************************
\r
303 * Function that enables the tracing and creates the control task. It will halt
\r
304 * execution until a Start command has been received if haltUntilStart is true.
\r
306 ******************************************************************************/
\r
307 void vTraceEnable(int startOption)
\r
311 extern uint32_t RecorderEnabled;
\r
312 TracealyzerCommandType msg;
\r
314 /* Only do this first time...*/
\r
315 if (HandleTzCtrl == NULL)
\r
317 TRC_STREAM_PORT_INIT();
\r
319 /* Note: Requires that TRC_CFG_INCLUDE_USER_EVENTS is 1. */
\r
320 trcWarningChannel = xTraceRegisterString("Warnings from Recorder");
\r
322 /* Creates the TzCtrl task - receives trace commands (start, stop, ...) */
\r
323 #if defined(configSUPPORT_STATIC_ALLOCATION) && (configSUPPORT_STATIC_ALLOCATION == 1)
\r
324 HandleTzCtrl = xTaskCreateStatic(TzCtrl, STRING_CAST("TzCtrl"), TRC_CFG_CTRL_TASK_STACK_SIZE, NULL, TRC_CFG_CTRL_TASK_PRIORITY, stackTzCtrl, &tcbTzCtrl);
\r
326 xTaskCreate( TzCtrl, STRING_CAST("TzCtrl"), TRC_CFG_CTRL_TASK_STACK_SIZE, NULL, TRC_CFG_CTRL_TASK_PRIORITY, &HandleTzCtrl );
\r
329 if (HandleTzCtrl == NULL)
\r
331 prvTraceError(PSF_ERROR_TZCTRLTASK_NOT_CREATED);
\r
335 if (startOption == TRC_START_AWAIT_HOST)
\r
337 /* We keep trying to read commands until the recorder has been started */
\r
342 status = TRC_STREAM_PORT_READ_DATA(&msg, sizeof(TracealyzerCommandType), (int32_t*)&bytes);
\r
346 prvTraceWarning(PSF_WARNING_STREAM_PORT_READ);
\r
349 if ((status == 0) && (bytes == sizeof(TracealyzerCommandType)))
\r
351 if (prvIsValidCommand(&msg))
\r
353 if (msg.cmdCode == CMD_SET_ACTIVE && msg.param1 == 1)
\r
355 /* On start, init and reset the timestamping */
\r
356 TRC_PORT_SPECIFIC_INIT();
\r
359 prvProcessCommand(&msg);
\r
363 while (RecorderEnabled == 0);
\r
365 else if (startOption == TRC_START)
\r
367 /* We start streaming directly - this assumes that the interface is ready! */
\r
368 TRC_PORT_SPECIFIC_INIT();
\r
370 msg.cmdCode = CMD_SET_ACTIVE;
\r
372 prvProcessCommand(&msg);
\r
377 TRC_PORT_SPECIFIC_INIT();
\r
381 #if (TRC_CFG_SCHEDULING_ONLY == 0)
\r
382 /*******************************************************************************
\r
383 * vTraceSetQueueName(void* object, const char* name)
\r
385 * Parameter object: pointer to the Queue that shall be named
\r
386 * Parameter name: the name to set (const string literal)
\r
388 * Sets a name for Queue objects for display in Tracealyzer.
\r
389 ******************************************************************************/
\r
390 void vTraceSetQueueName(void* object, const char* name)
\r
392 vTraceStoreKernelObjectName(object, name);
\r
395 /*******************************************************************************
\r
396 * vTraceSetSemaphoreName(void* object, const char* name)
\r
398 * Parameter object: pointer to the Semaphore that shall be named
\r
399 * Parameter name: the name to set (const string literal)
\r
401 * Sets a name for Semaphore objects for display in Tracealyzer.
\r
402 ******************************************************************************/
\r
403 void vTraceSetSemaphoreName(void* object, const char* name)
\r
405 vTraceStoreKernelObjectName(object, name);
\r
408 /*******************************************************************************
\r
409 * vTraceSetMutexName(void* object, const char* name)
\r
411 * Parameter object: pointer to the Mutex that shall be named
\r
412 * Parameter name: the name to set (const string literal)
\r
414 * Sets a name for Mutex objects for display in Tracealyzer.
\r
415 ******************************************************************************/
\r
416 void vTraceSetMutexName(void* object, const char* name)
\r
418 vTraceStoreKernelObjectName(object, name);
\r
421 #if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X)
\r
422 /*******************************************************************************
\r
423 * vTraceSetEventGroupName(void* object, const char* name)
\r
425 * Parameter object: pointer to the vTraceSetEventGroupName that shall be named
\r
426 * Parameter name: the name to set (const string literal)
\r
428 * Sets a name for EventGroup objects for display in Tracealyzer.
\r
429 ******************************************************************************/
\r
430 void vTraceSetEventGroupName(void* object, const char* name)
\r
432 vTraceStoreKernelObjectName(object, name);
\r
434 #endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */
\r
436 #if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0)
\r
437 /*******************************************************************************
\r
438 * vTraceSetStreamBufferName(void* object, const char* name)
\r
440 * Parameter object: pointer to the StreamBuffer that shall be named
\r
441 * Parameter name: the name to set (const string literal)
\r
443 * Sets a name for StreamBuffer objects for display in Tracealyzer.
\r
444 ******************************************************************************/
\r
445 void vTraceSetStreamBufferName(void* object, const char* name)
\r
447 vTraceStoreKernelObjectName(object, name);
\r
450 /*******************************************************************************
\r
451 * vTraceSetMessageBufferName(void* object, const char* name)
\r
453 * Parameter object: pointer to the MessageBuffer that shall be named
\r
454 * Parameter name: the name to set (const string literal)
\r
456 * Sets a name for MessageBuffer objects for display in Tracealyzer.
\r
457 ******************************************************************************/
\r
458 void vTraceSetMessageBufferName(void* object, const char* name)
\r
460 vTraceStoreKernelObjectName(object, name);
\r
462 #endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */
\r
464 #endif /* (TRC_CFG_SCHEDULING_ONLY == 0) */
\r
466 /*******************************************************************************
\r
467 * prvGetCurrentTaskHandle
\r
469 * Function that returns the handle to the currently executing task.
\r
471 ******************************************************************************/
\r
472 void* prvTraceGetCurrentTaskHandle(void)
\r
474 return xTaskGetCurrentTaskHandle();
\r
477 /*******************************************************************************
\r
480 * Tells if this task is already executing, or if there has been a task-switch.
\r
481 * Assumed to be called within a trace hook in kernel context.
\r
482 ******************************************************************************/
\r
483 uint32_t prvIsNewTCB(void* pNewTCB)
\r
485 if (pCurrentTCB != pNewTCB)
\r
487 pCurrentTCB = pNewTCB;
\r
493 /*******************************************************************************
\r
494 * prvTraceIsSchedulerSuspended
\r
496 * Returns true if the RTOS scheduler currently is disabled, thus preventing any
\r
497 * task-switches from occurring. Only called from vTraceStoreISREnd.
\r
498 ******************************************************************************/
\r
499 unsigned char prvTraceIsSchedulerSuspended(void)
\r
501 /* Assumed to be available in FreeRTOS. According to the FreeRTOS docs,
\r
502 INCLUDE_xTaskGetSchedulerState or configUSE_TIMERS must be set to 1 in
\r
503 FreeRTOSConfig.h for this function to be available. */
\r
505 return xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED;
\r
509 /*******************************************************************************
\r
510 * prvCheckRecorderStatus
\r
512 * Called by TzCtrl task periodically (every 100 ms - seems reasonable).
\r
513 * Checks a number of diagnostic variables and give warnings as user events,
\r
514 * in most cases including a suggested solution.
\r
515 ******************************************************************************/
\r
516 static void prvCheckRecorderStatus(void)
\r
518 if (NoRoomForSymbol > NoRoomForSymbol_last)
\r
520 if (NoRoomForSymbol > 0)
\r
522 prvTraceWarning(PSF_WARNING_SYMBOL_TABLE_SLOTS);
\r
524 NoRoomForSymbol_last = NoRoomForSymbol;
\r
527 if (NoRoomForObjectData > NoRoomForObjectData_last)
\r
529 if (NoRoomForObjectData > 0)
\r
531 prvTraceWarning(PSF_WARNING_OBJECT_DATA_SLOTS);
\r
533 NoRoomForObjectData_last = NoRoomForObjectData;
\r
536 if (LongestSymbolName > LongestSymbolName_last)
\r
538 if (LongestSymbolName > (TRC_CFG_SYMBOL_MAX_LENGTH))
\r
540 prvTraceWarning(PSF_WARNING_SYMBOL_MAX_LENGTH);
\r
542 LongestSymbolName_last = LongestSymbolName;
\r
545 if (MaxBytesTruncated > MaxBytesTruncated_last)
\r
547 if (MaxBytesTruncated > 0)
\r
549 prvTraceWarning(PSF_WARNING_STRING_TOO_LONG);
\r
551 MaxBytesTruncated_last = MaxBytesTruncated;
\r
555 /*******************************************************************************
\r
558 * Task for sending the trace data from the internal buffer to the stream
\r
559 * interface (assuming TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) and for
\r
560 * receiving commands from Tracealyzer. Also does some diagnostics.
\r
561 ******************************************************************************/
\r
562 static portTASK_FUNCTION( TzCtrl, pvParameters )
\r
564 TracealyzerCommandType msg;
\r
566 int32_t status = 0;
\r
567 (void)pvParameters;
\r
573 /* Listen for new commands */
\r
575 status = TRC_STREAM_PORT_READ_DATA(&msg, sizeof(TracealyzerCommandType), (int32_t*)&bytes);
\r
579 prvTraceWarning(PSF_WARNING_STREAM_PORT_READ);
\r
582 if ((status == 0) && (bytes == sizeof(TracealyzerCommandType)))
\r
584 if (prvIsValidCommand(&msg))
\r
586 prvProcessCommand(&msg); /* Start or Stop currently... */
\r
590 /* If the internal buffer is disabled, the COMMIT macro instead sends the data directly
\r
591 from the "event functions" (using TRC_STREAM_PORT_WRITE_DATA). */
\r
592 #if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1)
\r
593 /* If there is a buffer page, this sends it to the streaming interface using TRC_STREAM_PORT_WRITE_DATA. */
\r
594 bytes = prvPagedEventBufferTransfer();
\r
597 /* If there was data sent or received (bytes != 0), loop around and repeat, if there is more data to send or receive.
\r
598 Otherwise, step out of this loop and sleep for a while. */
\r
600 } while (bytes != 0);
\r
602 prvCheckRecorderStatus();
\r
604 vTaskDelay(TRC_CFG_CTRL_TASK_DELAY);
\r
608 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
\r
611 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
\r
613 /* Internal flag to tell the context of tracePEND_FUNC_CALL_FROM_ISR */
\r
614 int uiInEventGroupSetBitsFromISR = 0;
\r
616 /******************************************************************************
\r
617 * TraceQueueClassTable
\r
618 * Translates a FreeRTOS QueueType into trace objects classes (TRACE_CLASS_).
\r
619 * Has one entry for each QueueType, gives TRACE_CLASS ID.
\r
620 ******************************************************************************/
\r
621 traceObjectClass TraceQueueClassTable[5] = {
\r
624 TRACE_CLASS_SEMAPHORE,
\r
625 TRACE_CLASS_SEMAPHORE,
\r
629 #if (TRC_CFG_SCHEDULING_ONLY == 0)
\r
630 /*******************************************************************************
\r
631 * vTraceSetQueueName(void* object, const char* name)
\r
633 * Parameter object: pointer to the Queue that shall be named
\r
634 * Parameter name: the name to set (const string literal)
\r
636 * Sets a name for Queue objects for display in Tracealyzer.
\r
637 ******************************************************************************/
\r
638 void vTraceSetQueueName(void* object, const char* name)
\r
640 prvTraceSetObjectName(TRACE_CLASS_QUEUE, TRACE_GET_OBJECT_NUMBER(QUEUE, object), name);
\r
643 /*******************************************************************************
\r
644 * vTraceSetSemaphoreName(void* object, const char* name)
\r
646 * Parameter object: pointer to the Semaphore that shall be named
\r
647 * Parameter name: the name to set (const string literal)
\r
649 * Sets a name for Semaphore objects for display in Tracealyzer.
\r
650 ******************************************************************************/
\r
651 void vTraceSetSemaphoreName(void* object, const char* name)
\r
653 prvTraceSetObjectName(TRACE_CLASS_SEMAPHORE, TRACE_GET_OBJECT_NUMBER(QUEUE, object), name);
\r
656 /*******************************************************************************
\r
657 * vTraceSetMutexName(void* object, const char* name)
\r
659 * Parameter object: pointer to the Mutex that shall be named
\r
660 * Parameter name: the name to set (const string literal)
\r
662 * Sets a name for Semaphore objects for display in Tracealyzer.
\r
663 ******************************************************************************/
\r
664 void vTraceSetMutexName(void* object, const char* name)
\r
666 prvTraceSetObjectName(TRACE_CLASS_MUTEX, TRACE_GET_OBJECT_NUMBER(QUEUE, object), name);
\r
669 #if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X)
\r
670 /*******************************************************************************
\r
671 * vTraceSetEventGroupName(void* object, const char* name)
\r
673 * Parameter object: pointer to the EventGroup that shall be named
\r
674 * Parameter name: the name to set (const string literal)
\r
676 * Sets a name for EventGroup objects for display in Tracealyzer.
\r
677 ******************************************************************************/
\r
678 void vTraceSetEventGroupName(void* object, const char* name)
\r
680 prvTraceSetObjectName(TRACE_CLASS_EVENTGROUP, TRACE_GET_OBJECT_NUMBER(EVENTGROUP, object), name);
\r
682 #endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */
\r
684 #if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0)
\r
685 /*******************************************************************************
\r
686 * vTraceSetStreamBufferName(void* object, const char* name)
\r
688 * Parameter object: pointer to the StreamBuffer that shall be named
\r
689 * Parameter name: the name to set (const string literal)
\r
691 * Sets a name for StreamBuffer objects for display in Tracealyzer.
\r
692 ******************************************************************************/
\r
693 void vTraceSetStreamBufferName(void* object, const char* name)
\r
695 prvTraceSetObjectName(TRACE_CLASS_STREAMBUFFER, TRACE_GET_OBJECT_NUMBER(STREAMBUFFER, object), name);
\r
698 /*******************************************************************************
\r
699 * vTraceSetMessageBufferName(void* object, const char* name)
\r
701 * Parameter object: pointer to the MessageBuffer that shall be named
\r
702 * Parameter name: the name to set (const string literal)
\r
704 * Sets a name for MessageBuffer objects for display in Tracealyzer.
\r
705 ******************************************************************************/
\r
706 void vTraceSetMessageBufferName(void* object, const char* name)
\r
708 prvTraceSetObjectName(TRACE_CLASS_MESSAGEBUFFER, TRACE_GET_OBJECT_NUMBER(STREAMBUFFER, object), name);
\r
710 #endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */
\r
712 #endif /* (TRC_CFG_SCHEDULING_ONLY == 0) */
\r
714 void* prvTraceGetCurrentTaskHandle()
\r
716 return xTaskGetCurrentTaskHandle();
\r
719 /* Initialization of the object property table */
\r
720 void vTraceInitObjectPropertyTable()
\r
722 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectClasses = TRACE_NCLASSES;
\r
723 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[0] = TRC_CFG_NQUEUE;
\r
724 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[1] = TRC_CFG_NSEMAPHORE;
\r
725 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[2] = TRC_CFG_NMUTEX;
\r
726 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[3] = TRC_CFG_NTASK;
\r
727 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[4] = TRC_CFG_NISR;
\r
728 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[5] = TRC_CFG_NTIMER;
\r
729 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[6] = TRC_CFG_NEVENTGROUP;
\r
730 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[7] = TRC_CFG_NSTREAMBUFFER;
\r
731 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[8] = TRC_CFG_NMESSAGEBUFFER;
\r
732 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[0] = TRC_CFG_NAME_LEN_QUEUE;
\r
733 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[1] = TRC_CFG_NAME_LEN_SEMAPHORE;
\r
734 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[2] = TRC_CFG_NAME_LEN_MUTEX;
\r
735 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[3] = TRC_CFG_NAME_LEN_TASK;
\r
736 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[4] = TRC_CFG_NAME_LEN_ISR;
\r
737 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[5] = TRC_CFG_NAME_LEN_TIMER;
\r
738 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[6] = TRC_CFG_NAME_LEN_EVENTGROUP;
\r
739 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[7] = TRC_CFG_NAME_LEN_STREAMBUFFER;
\r
740 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[8] = TRC_CFG_NAME_LEN_MESSAGEBUFFER;
\r
741 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[0] = PropertyTableSizeQueue;
\r
742 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[1] = PropertyTableSizeSemaphore;
\r
743 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[2] = PropertyTableSizeMutex;
\r
744 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[3] = PropertyTableSizeTask;
\r
745 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[4] = PropertyTableSizeISR;
\r
746 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[5] = PropertyTableSizeTimer;
\r
747 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[6] = PropertyTableSizeEventGroup;
\r
748 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[7] = PropertyTableSizeStreamBuffer;
\r
749 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[8] = PropertyTableSizeMessageBuffer;
\r
750 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[0] = StartIndexQueue;
\r
751 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[1] = StartIndexSemaphore;
\r
752 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[2] = StartIndexMutex;
\r
753 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[3] = StartIndexTask;
\r
754 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[4] = StartIndexISR;
\r
755 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[5] = StartIndexTimer;
\r
756 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[6] = StartIndexEventGroup;
\r
757 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[7] = StartIndexStreamBuffer;
\r
758 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[8] = StartIndexMessageBuffer;
\r
759 RecorderDataPtr->ObjectPropertyTable.ObjectPropertyTableSizeInBytes = TRACE_OBJECT_TABLE_SIZE;
\r
762 /* Initialization of the handle mechanism, see e.g, prvTraceGetObjectHandle */
\r
763 void vTraceInitObjectHandleStack()
\r
765 objectHandleStacks.indexOfNextAvailableHandle[0] = objectHandleStacks.lowestIndexOfClass[0] = 0;
\r
766 objectHandleStacks.indexOfNextAvailableHandle[1] = objectHandleStacks.lowestIndexOfClass[1] = (TRC_CFG_NQUEUE);
\r
767 objectHandleStacks.indexOfNextAvailableHandle[2] = objectHandleStacks.lowestIndexOfClass[2] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE);
\r
768 objectHandleStacks.indexOfNextAvailableHandle[3] = objectHandleStacks.lowestIndexOfClass[3] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX);
\r
769 objectHandleStacks.indexOfNextAvailableHandle[4] = objectHandleStacks.lowestIndexOfClass[4] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK);
\r
770 objectHandleStacks.indexOfNextAvailableHandle[5] = objectHandleStacks.lowestIndexOfClass[5] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR);
\r
771 objectHandleStacks.indexOfNextAvailableHandle[6] = objectHandleStacks.lowestIndexOfClass[6] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER);
\r
772 objectHandleStacks.indexOfNextAvailableHandle[7] = objectHandleStacks.lowestIndexOfClass[7] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) + (TRC_CFG_NEVENTGROUP);
\r
773 objectHandleStacks.indexOfNextAvailableHandle[8] = objectHandleStacks.lowestIndexOfClass[8] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) + (TRC_CFG_NEVENTGROUP) + (TRC_CFG_NSTREAMBUFFER);
\r
775 objectHandleStacks.highestIndexOfClass[0] = (TRC_CFG_NQUEUE) - 1;
\r
776 objectHandleStacks.highestIndexOfClass[1] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) - 1;
\r
777 objectHandleStacks.highestIndexOfClass[2] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) - 1;
\r
778 objectHandleStacks.highestIndexOfClass[3] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) - 1;
\r
779 objectHandleStacks.highestIndexOfClass[4] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) - 1;
\r
780 objectHandleStacks.highestIndexOfClass[5] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) - 1;
\r
781 objectHandleStacks.highestIndexOfClass[6] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) + (TRC_CFG_NEVENTGROUP) - 1;
\r
782 objectHandleStacks.highestIndexOfClass[7] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) + (TRC_CFG_NEVENTGROUP) + (TRC_CFG_NSTREAMBUFFER) - 1;
\r
783 objectHandleStacks.highestIndexOfClass[8] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) + (TRC_CFG_NEVENTGROUP) + (TRC_CFG_NSTREAMBUFFER) + (TRC_CFG_NMESSAGEBUFFER) - 1;
\r
786 /* Returns the "Not enough handles" error message for this object class */
\r
787 const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass)
\r
789 switch(objectclass)
\r
791 case TRACE_CLASS_TASK:
\r
792 return "Not enough TASK handles - increase TRC_CFG_NTASK in trcSnapshotConfig.h";
\r
793 case TRACE_CLASS_ISR:
\r
794 return "Not enough ISR handles - increase TRC_CFG_NISR in trcSnapshotConfig.h";
\r
795 case TRACE_CLASS_SEMAPHORE:
\r
796 return "Not enough SEMAPHORE handles - increase TRC_CFG_NSEMAPHORE in trcSnapshotConfig.h";
\r
797 case TRACE_CLASS_MUTEX:
\r
798 return "Not enough MUTEX handles - increase TRC_CFG_NMUTEX in trcSnapshotConfig.h";
\r
799 case TRACE_CLASS_QUEUE:
\r
800 return "Not enough QUEUE handles - increase TRC_CFG_NQUEUE in trcSnapshotConfig.h";
\r
801 case TRACE_CLASS_TIMER:
\r
802 return "Not enough TIMER handles - increase TRC_CFG_NTIMER in trcSnapshotConfig.h";
\r
803 case TRACE_CLASS_EVENTGROUP:
\r
804 return "Not enough EVENTGROUP handles - increase TRC_CFG_NEVENTGROUP in trcSnapshotConfig.h";
\r
805 case TRACE_CLASS_STREAMBUFFER:
\r
806 return "Not enough STREAMBUFFER handles - increase TRC_CFG_NSTREAMBUFFER in trcSnapshotConfig.h";
\r
807 case TRACE_CLASS_MESSAGEBUFFER:
\r
808 return "Not enough MESSAGEBUFFER handles - increase TRC_CFG_NMESSAGEBUFFER in trcSnapshotConfig.h";
\r
810 return "pszTraceGetErrorHandles: Invalid objectclass!";
\r
814 /*******************************************************************************
\r
815 * prvTraceIsSchedulerSuspended
\r
817 * Returns true if the RTOS scheduler currently is disabled, thus preventing any
\r
818 * task-switches from occurring. Only called from vTraceStoreISREnd.
\r
819 ******************************************************************************/
\r
820 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
\r
821 unsigned char prvTraceIsSchedulerSuspended(void)
\r
823 /* Assumed to be available in FreeRTOS. According to the FreeRTOS docs,
\r
824 INCLUDE_xTaskGetSchedulerState or configUSE_TIMERS must be set to 1 in
\r
825 FreeRTOSConfig.h for this function to be available. */
\r
827 return xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED;
\r
831 #endif /* Snapshot mode */
\r
833 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
\r