1 /*
2 * Trace Recorder for Tracealyzer v4.5.1
3 * Copyright 2021 Percepio AB
4 * www.percepio.com
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 * uC/OS3 specific parts of the trace recorder
9 */
10
11 #include <os.h>
12 #include <lib_str.h>
13 #include "trcInternalBuffer.h"
14
15 #if (defined(TRC_USE_TRACEALYZER_RECORDER) && TRC_USE_TRACEALYZER_RECORDER == 1)
16
17 #if (OS_VERSION < 30700u)
18 /* This is used to keep track of the tick task so we are able to filter it */
19 void* prvTrcTickTask = 0;
20 #endif /* (OS_VERSION < 30700u) */
21
22 #include <stdint.h>
23
24 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) || (defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0))
25
26 /* TzCtrl task Stack and TCB */
27 static CPU_STK TzCtrlStk[TRC_CFG_CTRL_TASK_STACK_SIZE];
28 static OS_TCB TzCtrlTCB;
29 static OS_TCB* ptrTzCtrlTCB = NULL;
30
31 /* The TzCtrl task - receives commands from Tracealyzer (start/stop) */
32 static void TzCtrl (void *p_arg);
33
34 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
35 void prvReportStackUsage(void);
36 #else /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
37 #define prvReportStackUsage()
38 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
39
40 #endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) || (defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)) */
41
42 #define TRC_MAX_STRING_APPEND_SIZE 64
43
44 /* Variables to hold the latest suspended and resumed task */
45 static void* lastResumedTask = 0;
46 static void* lastSuspendedTask = 0;
47
prvTraceGetCurrentTaskHandle(void)48 void* prvTraceGetCurrentTaskHandle(void)
49 {
50 return (void*)OSTCBCurPtr; /* OSTCBCurPtr is a pointer to currently running TCB */
51 }
52
prvTraceAppend(const char * name,const char * suffix)53 char* prvTraceAppend(const char *name, const char *suffix)
54 {
55 static char buf[TRC_MAX_STRING_APPEND_SIZE];
56 uint32_t i = 0, j = 0;
57
58 /* (i < ((TRC_MAX_STRING_APPEND_SIZE) - 2)) leaves room for ' ' and null termination */
59 while ((i < ((TRC_MAX_STRING_APPEND_SIZE) - 2)) && (name[i] != 0))
60 {
61 buf[i] = name[i];
62 i++;
63 }
64
65 buf[i] = ' ';
66 i++;
67
68 /* (i < ((TRC_MAX_STRING_APPEND_SIZE) - 1)) leaves room for null termination */
69 while ((i < ((TRC_MAX_STRING_APPEND_SIZE) - 1)) && (suffix[j] != 0))
70 {
71 buf[i] = suffix[j];
72 i++;
73 j++;
74 }
75
76 /* Always null termination */
77 buf[i] = 0;
78
79 return (&buf[0]);
80 }
81
82 /* Tasks */
prvTraceGetTaskNumberLow16(void * handle)83 uint16_t prvTraceGetTaskNumberLow16(void* handle)
84 {
85 if (handle == 0)
86 return 0;
87
88 return TRACE_GET_LOW16(((OS_TCB*)handle)->TaskID);
89 }
90
prvTraceGetTaskNumberHigh16(void * handle)91 uint16_t prvTraceGetTaskNumberHigh16(void* handle)
92 {
93 return TRACE_GET_HIGH16(((OS_TCB*)handle)->TaskID);
94 }
95
prvTraceSetTaskNumberLow16(void * handle,uint16_t value)96 void prvTraceSetTaskNumberLow16(void* handle, uint16_t value)
97 {
98 ((OS_TCB*)handle)->TaskID = TRACE_SET_LOW16(((OS_TCB*)handle)->TaskID, value);
99 }
100
prvTraceSetTaskNumberHigh16(void * handle,uint16_t value)101 void prvTraceSetTaskNumberHigh16(void* handle, uint16_t value)
102 {
103 ((OS_TCB*)handle)->TaskID = TRACE_SET_HIGH16(((OS_TCB*)handle)->TaskID, value);
104 }
105
106 /* Task Queues */
107 #if (OS_CFG_TASK_Q_EN == DEF_ENABLED)
prvTraceGetTaskQueueNumberLow16(void * handle)108 uint16_t prvTraceGetTaskQueueNumberLow16(void* handle)
109 {
110 return TRACE_GET_LOW16(((OS_MSG_Q *)handle)->MsgQID);
111 }
112
prvTraceGetTaskQueueNumberHigh16(void * handle)113 uint16_t prvTraceGetTaskQueueNumberHigh16(void* handle)
114 {
115 return TRACE_GET_HIGH16(((OS_MSG_Q *)handle)->MsgQID);
116 }
117
prvTraceSetTaskQueueNumberLow16(void * handle,uint16_t value)118 void prvTraceSetTaskQueueNumberLow16(void* handle, uint16_t value)
119 {
120 ((OS_MSG_Q *)handle)->MsgQID = TRACE_SET_LOW16(((OS_MSG_Q *)handle)->MsgQID, value);
121 }
122
prvTraceSetTaskQueueNumberHigh16(void * handle,uint16_t value)123 void prvTraceSetTaskQueueNumberHigh16(void* handle, uint16_t value)
124 {
125 ((OS_MSG_Q *)handle)->MsgQID = TRACE_SET_HIGH16(((OS_MSG_Q *)handle)->MsgQID, value);
126 }
127 #endif /* (OS_CFG_TASK_Q_EN == DEF_ENABLED) */
128
129 /* Task Semaphores */
prvTraceGetTaskSemNumberLow16(void * handle)130 uint16_t prvTraceGetTaskSemNumberLow16(void* handle)
131 {
132 return TRACE_GET_LOW16(((OS_TCB *)handle)->SemID);
133 }
134
prvTraceGetTaskSemNumberHigh16(void * handle)135 uint16_t prvTraceGetTaskSemNumberHigh16(void* handle)
136 {
137 return TRACE_GET_HIGH16(((OS_TCB *)handle)->SemID);
138 }
139
prvTraceSetTaskSemNumberLow16(void * handle,uint16_t value)140 void prvTraceSetTaskSemNumberLow16(void* handle, uint16_t value)
141 {
142 ((OS_TCB *)handle)->SemID = TRACE_SET_LOW16(((OS_TCB *)handle)->SemID, value);
143 }
144
prvTraceSetTaskSemNumberHigh16(void * handle,uint16_t value)145 void prvTraceSetTaskSemNumberHigh16(void* handle, uint16_t value)
146 {
147 ((OS_TCB *)handle)->SemID = TRACE_SET_HIGH16(((OS_TCB *)handle)->SemID, value);
148 }
149
150 /* Queues */
prvTraceGetQueueNumberLow16(void * handle)151 uint16_t prvTraceGetQueueNumberLow16(void* handle)
152 {
153 return TRACE_GET_LOW16(((OS_Q*)handle)->MsgQ.MsgQID);
154 }
155
prvTraceGetQueueNumberHigh16(void * handle)156 uint16_t prvTraceGetQueueNumberHigh16(void* handle)
157 {
158 return TRACE_GET_HIGH16(((OS_Q*)handle)->MsgQ.MsgQID);
159 }
160
prvTraceSetQueueNumberLow16(void * handle,uint16_t value)161 void prvTraceSetQueueNumberLow16(void* handle, uint16_t value)
162 {
163 ((OS_Q*)handle)->MsgQ.MsgQID = TRACE_SET_LOW16(((OS_Q*)handle)->MsgQ.MsgQID, value);
164 }
165
prvTraceSetQueueNumberHigh16(void * handle,uint16_t value)166 void prvTraceSetQueueNumberHigh16(void* handle, uint16_t value)
167 {
168 ((OS_Q*)handle)->MsgQ.MsgQID = TRACE_SET_HIGH16(((OS_Q*)handle)->MsgQ.MsgQID, value);
169 }
170
171 /* Semaphores */
prvTraceGetSemaphoreNumberLow16(void * handle)172 uint16_t prvTraceGetSemaphoreNumberLow16(void* handle)
173 {
174 return TRACE_GET_LOW16(((OS_SEM*)handle)->SemID);
175 }
176
prvTraceGetSemaphoreNumberHigh16(void * handle)177 uint16_t prvTraceGetSemaphoreNumberHigh16(void* handle)
178 {
179 return TRACE_GET_HIGH16(((OS_SEM*)handle)->SemID);
180 }
181
prvTraceSetSemaphoreNumberLow16(void * handle,uint16_t value)182 void prvTraceSetSemaphoreNumberLow16(void* handle, uint16_t value)
183 {
184 ((OS_SEM*)handle)->SemID = TRACE_SET_LOW16(((OS_SEM*)handle)->SemID, value);
185 }
186
prvTraceSetSemaphoreNumberHigh16(void * handle,uint16_t value)187 void prvTraceSetSemaphoreNumberHigh16(void* handle, uint16_t value)
188 {
189 ((OS_SEM*)handle)->SemID = TRACE_SET_HIGH16(((OS_SEM*)handle)->SemID, value);
190 }
191
192 /* Mutexes */
prvTraceGetMutexNumberLow16(void * handle)193 uint16_t prvTraceGetMutexNumberLow16(void* handle)
194 {
195 return TRACE_GET_LOW16(((OS_MUTEX*)handle)->MutexID);
196 }
197
prvTraceGetMutexNumberHigh16(void * handle)198 uint16_t prvTraceGetMutexNumberHigh16(void* handle)
199 {
200 return TRACE_GET_HIGH16(((OS_MUTEX*)handle)->MutexID);
201 }
202
prvTraceSetMutexNumberLow16(void * handle,uint16_t value)203 void prvTraceSetMutexNumberLow16(void* handle, uint16_t value)
204 {
205 ((OS_MUTEX*)handle)->MutexID = TRACE_SET_LOW16(((OS_MUTEX*)handle)->MutexID, value);
206 }
207
prvTraceSetMutexNumberHigh16(void * handle,uint16_t value)208 void prvTraceSetMutexNumberHigh16(void* handle, uint16_t value)
209 {
210 ((OS_MUTEX*)handle)->MutexID = TRACE_SET_HIGH16(((OS_MUTEX*)handle)->MutexID, value);
211 }
212
213 /* Flags */
prvTraceGetFlagNumberLow16(void * handle)214 uint16_t prvTraceGetFlagNumberLow16(void* handle)
215 {
216 return TRACE_GET_LOW16(((OS_FLAG_GRP*)handle)->FlagID);
217 }
218
prvTraceGetFlagNumberHigh16(void * handle)219 uint16_t prvTraceGetFlagNumberHigh16(void* handle)
220 {
221 return TRACE_GET_HIGH16(((OS_FLAG_GRP*)handle)->FlagID);
222 }
223
prvTraceSetFlagNumberLow16(void * handle,uint16_t value)224 void prvTraceSetFlagNumberLow16(void* handle, uint16_t value)
225 {
226 ((OS_FLAG_GRP*)handle)->FlagID = TRACE_SET_LOW16(((OS_FLAG_GRP*)handle)->FlagID, value);
227 }
228
prvTraceSetFlagNumberHigh16(void * handle,uint16_t value)229 void prvTraceSetFlagNumberHigh16(void* handle, uint16_t value)
230 {
231 ((OS_FLAG_GRP*)handle)->FlagID = TRACE_SET_HIGH16(((OS_FLAG_GRP*)handle)->FlagID, value);
232 }
233
234 /* Mems */
prvTraceGetMemNumberLow16(void * handle)235 uint16_t prvTraceGetMemNumberLow16(void* handle)
236 {
237 return TRACE_GET_LOW16(((OS_MEM*)handle)->MemID);
238 }
239
prvTraceGetMemNumberHigh16(void * handle)240 uint16_t prvTraceGetMemNumberHigh16(void* handle)
241 {
242 return TRACE_GET_HIGH16(((OS_MEM*)handle)->MemID);
243 }
244
prvTraceSetMemNumberLow16(void * handle,uint16_t value)245 void prvTraceSetMemNumberLow16(void* handle, uint16_t value)
246 {
247 ((OS_MEM*)handle)->MemID = TRACE_SET_LOW16(((OS_MEM*)handle)->MemID, value);
248 }
249
prvTraceSetMemNumberHigh16(void * handle,uint16_t value)250 void prvTraceSetMemNumberHigh16(void* handle, uint16_t value)
251 {
252 ((OS_MEM*)handle)->MemID = TRACE_SET_HIGH16(((OS_MEM*)handle)->MemID, value);
253 }
254
255 /* Suspend and resume */
prvTraceTaskSuspendEnter(void * p_tcb)256 void prvTraceTaskSuspendEnter(void* p_tcb)
257 {
258 TRACE_ALLOC_CRITICAL_SECTION();
259 TRACE_ENTER_CRITICAL_SECTION();
260 lastSuspendedTask = p_tcb;
261 }
262
prvTraceTaskSuspendExit(uint32_t p_err)263 void prvTraceTaskSuspendExit(uint32_t p_err)
264 {
265 if(p_err == OS_ERR_NONE){
266 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
267 if (lastSuspendedTask == 0)
268 {
269 trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND, OSTCBCurPtr);
270 }
271 else
272 {
273 trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND, lastSuspendedTask);
274 }
275 #else
276 if (lastSuspendedTask == 0)
277 {
278 prvTraceStoreEvent1(PSF_EVENT_TASK_SUSPEND, (uint32_t)OSTCBCurPtr);
279 }
280 else
281 {
282 prvTraceStoreEvent1(PSF_EVENT_TASK_SUSPEND, lastSuspendedTask);
283 }
284 #endif
285 }
286 else{
287 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
288 if (lastSuspendedTask == 0)
289 {
290 trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND_FAIL, OSTCBCurPtr);
291 }
292 else
293 {
294 trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND_FAIL, lastSuspendedTask);
295 }
296 #else
297 if (lastSuspendedTask == 0)
298 {
299 prvTraceStoreEvent1(PSF_EVENT_TASK_SUSPEND_FAILED, (uint32_t)OSTCBCurPtr);
300 }
301 else
302 {
303 prvTraceStoreEvent1(PSF_EVENT_TASK_SUSPEND_FAILED, lastSuspendedTask);
304 }
305 #endif
306 }
307 TRACE_ALLOC_CRITICAL_SECTION();
308 TRACE_EXIT_CRITICAL_SECTION();
309 }
prvTraceTaskResumeEnter(void * p_tcb)310 void prvTraceTaskResumeEnter(void* p_tcb)
311 {
312 TRACE_ALLOC_CRITICAL_SECTION();
313 TRACE_ENTER_CRITICAL_SECTION();
314 lastResumedTask = p_tcb;
315 }
316
prvTraceTaskResumeExit(uint32_t p_err)317 void prvTraceTaskResumeExit(uint32_t p_err)
318 {
319 if(p_err == OS_ERR_NONE){
320 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
321 trcKERNEL_HOOKS_TASK_RESUME(TASK_RESUME, lastResumedTask);
322 #else
323 prvTraceStoreEvent1(PSF_EVENT_TASK_RESUME, lastResumedTask);
324 #endif
325 }
326 else{
327 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
328 trcKERNEL_HOOKS_TASK_RESUME(TASK_RESUME_FAIL, lastResumedTask);
329 #else
330 prvTraceStoreEvent1(PSF_EVENT_TASK_RESUME_FAILED, lastResumedTask);
331 #endif
332 }
333 TRACE_ALLOC_CRITICAL_SECTION();
334 TRACE_EXIT_CRITICAL_SECTION();
335 }
336
337
338 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
prvTraceGetStackHighWaterMark(void * task)339 uint32_t prvTraceGetStackHighWaterMark(void* task)
340 {
341 CPU_STK_SIZE free = 0, used = 0;
342 OS_ERR err;
343
344 OSTaskStkChk(task, &free, &used, &err);
345
346 return free;
347 }
348 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
349
350 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
351
352 static void* pCurrentTCB = NULL;
353
354 /* Monitored by TzCtrl task, that give warnings as User Events */
355 extern volatile uint32_t NoRoomForSymbol;
356 extern volatile uint32_t NoRoomForObjectData;
357 extern volatile uint32_t LongestSymbolName;
358 extern volatile uint32_t MaxBytesTruncated;
359 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
360 extern volatile uint32_t TaskStacksNotIncluded;
361 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
362
363 /* User Event Channel for giving warnings regarding NoRoomForSymbol etc. */
364 traceString trcWarningChannel = 0;
365
366 TRC_STREAM_PORT_ALLOCATE_FIELDS()
367
368 /* Called by TzCtrl task periodically (Normally every 100 ms) */
369 static void prvCheckRecorderStatus(void);
370
371 extern void prvTraceWarning(int errCode);
372
373 /*******************************************************************************
374 * vTraceEnable
375 *
376 * Function that enables the tracing and creates the control task. It will halt
377 * execution until a Start command has been received if haltUntilStart is true.
378 *
379 ******************************************************************************/
vTraceEnable(int startOption)380 void vTraceEnable(int startOption)
381 {
382 OS_ERR err;
383 int32_t bytes = 0;
384 int32_t status;
385 TracealyzerCommandType msg;
386 extern uint32_t RecorderEnabled;
387
388 /* Make sure recorder data is initialized */
389 vTraceInitialize();
390
391 if (ptrTzCtrlTCB == 0)
392 {
393 TRC_STREAM_PORT_INIT();
394
395 /* The #WFR channel means "Warnings from Recorder" and
396 * is used to store warnings and errors from the recorder.
397 * The abbreviation #WFR is used instead of the longer full name,
398 * to avoid truncation by small slots in the symbol table.
399 * This is translated in Tracealyzer and shown as the full name,
400 * "Warnings from Recorder".
401 *
402 * Note: Requires that TRC_CFG_INCLUDE_USER_EVENTS is 1. */
403 trcWarningChannel = xTraceRegisterString("#WFR");
404
405 /* Creates the TzCtrl task - receives trace commands (start, stop, ...) */
406 OSTaskCreate((OS_TCB *)&TzCtrlTCB, /* Create the control task */
407 (CPU_CHAR *)"Tracealyzer Control Task",
408 (OS_TASK_PTR ) TzCtrl,
409 (void *) 0,
410 (OS_PRIO ) (TRC_CFG_CTRL_TASK_PRIORITY),
411 (CPU_STK *)&TzCtrlStk[0],
412 (CPU_STK_SIZE) (TRC_CFG_CTRL_TASK_STACK_SIZE) / 10u,
413 (CPU_STK_SIZE) (TRC_CFG_CTRL_TASK_STACK_SIZE),
414 (OS_MSG_QTY ) 0u,
415 (OS_TICK ) 0u,
416 (void *) 0,
417 (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
418 (OS_ERR *)&err);
419
420 ptrTzCtrlTCB = &TzCtrlTCB;
421 }
422
423 if (startOption == TRC_START_AWAIT_HOST)
424 {
425 /* We keep trying to read commands until the recorder has been started */
426 do
427 {
428 bytes = 0;
429
430 status = TRC_STREAM_PORT_READ_DATA(&msg, sizeof(TracealyzerCommandType), (int32_t*)&bytes);
431
432 if (status != 0)
433 {
434 prvTraceWarning(PSF_WARNING_STREAM_PORT_READ);
435 }
436
437 if ((status == 0) && (bytes == sizeof(TracealyzerCommandType)))
438 {
439 if (prvIsValidCommand(&msg))
440 {
441 if (msg.cmdCode == CMD_SET_ACTIVE && msg.param1 == 1)
442 {
443 /* On start, init and reset the timestamping */
444 TRC_PORT_SPECIFIC_INIT();
445 }
446
447 prvProcessCommand(&msg);
448 }
449 }
450 }
451 while (RecorderEnabled == 0);
452 }
453 else if (startOption == TRC_START)
454 {
455 /* We start streaming directly - this assumes that the interface is ready! */
456 TRC_PORT_SPECIFIC_INIT();
457
458 msg.cmdCode = CMD_SET_ACTIVE;
459 msg.param1 = 1;
460 prvProcessCommand(&msg);
461 }
462 else if (startOption == TRC_INIT)
463 {
464 /* On TRC_INIT */
465 TRC_PORT_SPECIFIC_INIT();
466 }
467 }
468
469 /*******************************************************************************
470 * prvTraceOnBegin
471 *
472 * Called on trace begin.
473 ******************************************************************************/
prvTraceOnBegin()474 void prvTraceOnBegin()
475 {
476 TRC_STREAM_PORT_ON_TRACE_BEGIN();
477 }
478
479 /*******************************************************************************
480 * prvTraceOnEnd
481 *
482 * Called on trace end.
483 ******************************************************************************/
prvTraceOnEnd()484 void prvTraceOnEnd()
485 {
486 TRC_STREAM_PORT_ON_TRACE_END();
487 }
488
489 /*******************************************************************************
490 * prvIsNewTCB
491 *
492 * Tells if this task is already executing, or if there has been a task-switch.
493 * Assumed to be called within a trace hook in kernel context.
494 ******************************************************************************/
prvIsNewTCB(void * pNewTCB)495 uint32_t prvIsNewTCB(void* pNewTCB)
496 {
497 if (pCurrentTCB != pNewTCB)
498 {
499 pCurrentTCB = pNewTCB;
500 return 1;
501 }
502 return 0;
503 }
504
505 /*******************************************************************************
506 * prvTraceIsSchedulerSuspended
507 *
508 * Returns true if the RTOS scheduler currently is disabled, thus preventing any
509 * task-switches from occurring. Only called from vTraceStoreISREnd.
510 ******************************************************************************/
prvTraceIsSchedulerSuspended(void)511 unsigned char prvTraceIsSchedulerSuspended(void)
512 {
513 return OSRunning != OS_STATE_OS_STOPPED;
514 }
515
516
517 /*******************************************************************************
518 * prvCheckRecorderStatus
519 *
520 * Called by TzCtrl task periodically (every 100 ms - seems reasonable).
521 * Checks a number of diagnostic variables and give warnings as user events,
522 * in most cases including a suggested solution.
523 ******************************************************************************/
prvCheckRecorderStatus(void)524 static void prvCheckRecorderStatus(void)
525 {
526 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
527 if (TaskStacksNotIncluded > 0)
528 {
529 prvTraceWarning(PSF_WARNING_STACKMON_NO_SLOTS);
530 TaskStacksNotIncluded = 0;
531 }
532 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
533
534 if (NoRoomForSymbol > 0)
535 {
536 prvTraceWarning(PSF_WARNING_SYMBOL_TABLE_SLOTS);
537 NoRoomForSymbol = 0;
538 }
539
540 if (NoRoomForObjectData > 0)
541 {
542 prvTraceWarning(PSF_WARNING_OBJECT_DATA_SLOTS);
543 NoRoomForObjectData = 0;
544 }
545
546 if (LongestSymbolName > (TRC_CFG_SYMBOL_MAX_LENGTH))
547 {
548 prvTraceWarning(PSF_WARNING_SYMBOL_MAX_LENGTH);
549 LongestSymbolName = 0;
550 }
551
552 if (MaxBytesTruncated > 0)
553 {
554 prvTraceWarning(PSF_WARNING_STRING_TOO_LONG);
555 MaxBytesTruncated = 0;
556 }
557 }
558
559 /*******************************************************************************
560 * TzCtrl
561 *
562 * Task for sending the trace data from the internal buffer to the stream
563 * interface (assuming TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) and for
564 * receiving commands from Tracealyzer. Also does some diagnostics.
565 ******************************************************************************/
TzCtrl(void * p_arg)566 static void TzCtrl(void *p_arg)
567 {
568 OS_ERR err;
569
570 TracealyzerCommandType msg;
571 int32_t bytes = 0;
572 int32_t status = 0;
573 (void)p_arg;
574
575 while (1)
576 {
577 do
578 {
579 /* Listen for new commands */
580 bytes = 0;
581 status = TRC_STREAM_PORT_READ_DATA(&msg, sizeof(TracealyzerCommandType), (int32_t*)&bytes);
582
583 if (status != 0)
584 {
585 /* The connection has failed, stop tracing */
586 vTraceStop();
587 }
588
589 if ((status == 0) && (bytes == sizeof(TracealyzerCommandType)))
590 {
591 if (prvIsValidCommand(&msg))
592 {
593 prvProcessCommand(&msg); /* Start or Stop currently... */
594 }
595 }
596
597 /* If the internal buffer is disabled, the COMMIT macro instead sends the data directly
598 from the "event functions" (using TRC_STREAM_PORT_WRITE_DATA). */
599 #if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1)
600 /* If there is a buffer page, this sends it to the streaming interface using TRC_STREAM_PORT_WRITE_DATA. */
601 bytes = prvPagedEventBufferTransfer();
602 #endif
603
604 /* If there was data sent or received (bytes != 0), loop around and repeat, if there is more data to send or receive.
605 Otherwise, step out of this loop and sleep for a while. */
606
607 } while (bytes != 0);
608
609 if (xTraceIsRecordingEnabled())
610 {
611 prvCheckRecorderStatus();
612 prvReportStackUsage();
613 }
614
615 OSTimeDly(TRC_CFG_CTRL_TASK_DELAY, OS_OPT_TIME_DLY, &err); /* 10ms */
616 }
617 }
618
619 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
620
621
622 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
623
624 /* Initialization of the object property table */
vTraceInitObjectPropertyTable()625 void vTraceInitObjectPropertyTable()
626 {
627 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectClasses = TRACE_NCLASSES;
628 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[0] = TRC_CFG_NQUEUE;
629 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[1] = TRC_CFG_NSEMAPHORE;
630 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[2] = TRC_CFG_NMUTEX;
631 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[3] = TRC_CFG_NFLAG;
632 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[4] = TRC_CFG_NMEM;
633 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[5] = TRC_CFG_NTASK_SEM;
634 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[6] = TRC_CFG_NTASK_Q;
635 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[7] = TRC_CFG_NTASK;
636 RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[8] = TRC_CFG_NISR;
637 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[0] = TRC_CFG_NAME_LEN_QUEUE;
638 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[1] = TRC_CFG_NAME_LEN_SEMAPHORE;
639 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[2] = TRC_CFG_NAME_LEN_MUTEX;
640 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[3] = TRC_CFG_NAME_LEN_FLAG;
641 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[4] = TRC_CFG_NAME_LEN_MEM;
642 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[5] = TRC_CFG_NAME_LEN_TASK_SEM;
643 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[6] = TRC_CFG_NAME_LEN_TASK_Q;
644 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[7] = TRC_CFG_NAME_LEN_TASK;
645 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[8] = TRC_CFG_NAME_LEN_ISR;
646 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[0] = PropertyTableSizeQueue;
647 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[1] = PropertyTableSizeSemaphore;
648 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[2] = PropertyTableSizeMutex;
649 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[3] = PropertyTableSizeFlag;
650 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[4] = PropertyTableSizeMem;
651 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[5] = PropertyTableSizeTaskSem;
652 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[6] = PropertyTableSizeTaskQ;
653 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[7] = PropertyTableSizeTask;
654 RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[8] = PropertyTableSizeISR;
655 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[0] = StartIndexQueue;
656 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[1] = StartIndexSemaphore;
657 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[2] = StartIndexMutex;
658 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[3] = StartIndexFlag;
659 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[4] = StartIndexMem;
660 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[5] = StartIndexTaskSem;
661 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[6] = StartIndexTaskQ;
662 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[7] = StartIndexTask;
663 RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[8] = StartIndexISR;
664 RecorderDataPtr->ObjectPropertyTable.ObjectPropertyTableSizeInBytes = TRACE_OBJECT_TABLE_SIZE;
665 }
666
667 /* Initialization of the handle mechanism, see e.g, prvTraceGetObjectHandle */
vTraceInitObjectHandleStack()668 void vTraceInitObjectHandleStack()
669 {
670 uint32_t i = 0;
671
672 objectHandleStacks.indexOfNextAvailableHandle[0] = objectHandleStacks.lowestIndexOfClass[0] = 0;
673 objectHandleStacks.indexOfNextAvailableHandle[1] = objectHandleStacks.lowestIndexOfClass[1] = (TRC_CFG_NQUEUE);
674 objectHandleStacks.indexOfNextAvailableHandle[2] = objectHandleStacks.lowestIndexOfClass[2] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE);
675 objectHandleStacks.indexOfNextAvailableHandle[3] = objectHandleStacks.lowestIndexOfClass[3] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX);
676 objectHandleStacks.indexOfNextAvailableHandle[4] = objectHandleStacks.lowestIndexOfClass[4] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG);
677 objectHandleStacks.indexOfNextAvailableHandle[5] = objectHandleStacks.lowestIndexOfClass[5] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM);
678 objectHandleStacks.indexOfNextAvailableHandle[6] = objectHandleStacks.lowestIndexOfClass[6] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM);
679 objectHandleStacks.indexOfNextAvailableHandle[7] = objectHandleStacks.lowestIndexOfClass[7] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM) + (TRC_CFG_NTASK_Q);
680 objectHandleStacks.indexOfNextAvailableHandle[8] = objectHandleStacks.lowestIndexOfClass[8] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM) + (TRC_CFG_NTASK_Q) + (TRC_CFG_NTASK);
681
682 objectHandleStacks.highestIndexOfClass[0] = (TRC_CFG_NQUEUE) - 1;
683 objectHandleStacks.highestIndexOfClass[1] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) - 1;
684 objectHandleStacks.highestIndexOfClass[2] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) - 1;
685 objectHandleStacks.highestIndexOfClass[3] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) - 1;
686 objectHandleStacks.highestIndexOfClass[4] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) - 1;
687 objectHandleStacks.highestIndexOfClass[5] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM) - 1;
688 objectHandleStacks.highestIndexOfClass[6] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM) + (TRC_CFG_NTASK_Q) - 1;
689 objectHandleStacks.highestIndexOfClass[7] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM) + (TRC_CFG_NTASK_Q) + (TRC_CFG_NTASK) - 1;
690 objectHandleStacks.highestIndexOfClass[8] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM) + (TRC_CFG_NTASK_Q) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) - 1;
691
692 for (i = 0; i < TRACE_NCLASSES; i++)
693 {
694 objectHandleStacks.handleCountWaterMarksOfClass[i] = 0;
695 }
696
697 for (i = 0; i < TRACE_KERNEL_OBJECT_COUNT; i++)
698 {
699 objectHandleStacks.objectHandles[i] = 0;
700 }
701 }
702
703 /******************************************************************************
704 * vTraceEnable(int startOption) - snapshot mode
705 *
706 * Initializes and optionally starts the trace, depending on the start option.
707 * To use the trace recorder, the startup must call vTraceEnable before any RTOS
708 * calls are made (including "create" calls). Three start options are provided:
709 *
710 * TRC_START: Starts the tracing directly. In snapshot mode this allows for
711 * starting the trace at any point in your code, assuming vTraceEnable(TRC_INIT)
712 * has been called in the startup.
713 * Can also be used for streaming without Tracealyzer control, e.g. to a local
714 * flash file system (assuming such a "stream port", see trcStreamingPort.h).
715 *
716 * TRC_INIT: Initializes the trace recorder, but does not start the tracing.
717 * In snapshot mode, this must be followed by a vTraceEnable(TRC_START) sometime
718 * later.
719 *
720 * Usage examples, in snapshot mode:
721 *
722 * Snapshot trace, from startup:
723 * <board init>
724 * vTraceEnable(TRC_START);
725 * <RTOS init>
726 *
727 * Snapshot trace, from a later point:
728 * <board init>
729 * vTraceEnable(TRC_INIT);
730 * <RTOS init>
731 * ...
732 * vTraceEnable(TRC_START); // e.g., in task context, at some relevant event
733 *
734 *
735 * Note: See other implementation of vTraceEnable in trcStreamingRecorder.c
736 ******************************************************************************/
vTraceEnable(int startOption)737 void vTraceEnable(int startOption)
738 {
739 /* Make sure recorder data is initialized */
740 vTraceInitialize();
741
742 if (startOption == TRC_START)
743 {
744 prvTraceInitTimestamps();
745
746 vTraceStart();
747 }
748 else if (startOption == TRC_START_AWAIT_HOST)
749 {
750 prvTraceError("vTraceEnable(TRC_START_AWAIT_HOST) not allowed in Snapshot mode");
751 }
752 else if (startOption != TRC_INIT)
753 {
754 prvTraceError("Unexpected argument to vTraceEnable (snapshot mode)");
755 }
756 }
757
758 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
759 /******************************************************************************
760 * vTraceStartStackMonitor()
761 *
762 * Starts the TzCtrl task which reports stack usage.
763 * This must be called after OSInit().
764 ******************************************************************************/
vTraceStartStackMonitor()765 void vTraceStartStackMonitor()
766 {
767 OS_ERR err;
768
769 if (ptrTzCtrlTCB == NULL)
770 {
771 /* Creates the TzCtrl task - reports unsed stack */
772 OSTaskCreate((OS_TCB *) &TzCtrlTCB, /* Create the control task */
773 (CPU_CHAR *) "TzCtrl",
774 (OS_TASK_PTR ) TzCtrl,
775 (void *) 0,
776 (OS_PRIO ) (TRC_CFG_CTRL_TASK_PRIORITY),
777 (CPU_STK *) &TzCtrlStk[0],
778 (CPU_STK_SIZE) (TRC_CFG_CTRL_TASK_STACK_SIZE) / 10u,
779 (CPU_STK_SIZE) (TRC_CFG_CTRL_TASK_STACK_SIZE),
780 (OS_MSG_QTY ) 0u,
781 (OS_TICK ) 0u,
782 (void *) 0,
783 (OS_OPT ) (OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
784 (OS_ERR *) &err);
785
786 ptrTzCtrlTCB = &TzCtrlTCB;
787 }
788 }
789 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
790
791 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
792 /*******************************************************************************
793 * TzCtrl
794 *
795 * Task used for reporting the stack usage for each task.
796 ******************************************************************************/
TzCtrl(void * p_arg)797 static void TzCtrl(void *p_arg)
798 {
799 OS_ERR err;
800
801 (void)p_arg;
802
803 while (1)
804 {
805 if (xTraceIsRecordingEnabled())
806 {
807 prvReportStackUsage();
808 }
809
810 OSTimeDly(TRC_CFG_CTRL_TASK_DELAY, OS_OPT_TIME_DLY, &err);
811 }
812 }
813 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
814
815 /* Returns the "Not enough handles" error message for this object class */
pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass)816 const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass)
817 {
818 switch(objectclass)
819 {
820 case TRACE_CLASS_QUEUE:
821 return "Not enough QUEUE handles - increase TRC_CFG_NQUEUE in trcSnapshotConfig.h";
822 case TRACE_CLASS_SEMAPHORE:
823 return "Not enough SEMAPHORE handles - increase TRC_CFG_NSEMAPHORE in trcSnapshotConfig.h";
824 case TRACE_CLASS_MUTEX:
825 return "Not enough MUTEX handles - increase TRC_CFG_NMUTEX in trcSnapshotConfig.h";
826 case TRACE_CLASS_FLAG:
827 return "Not enough FLAG handles - increase TRC_CFG_NFLAG in trcSnapshotConfig.h";
828 case TRACE_CLASS_MEM:
829 return "Not enough MEM handles - increase TRC_CFG_NMEM in trcSnapshotConfig.h";
830 case TRACE_CLASS_TASK_SEM:
831 return "Not enough TASK_SEM handles - increase TRC_CFG_NTASK_SEM in trcSnapshotConfig.h";
832 case TRACE_CLASS_TASK_Q:
833 return "Not enough TASK_Q handles - increase TRC_CFG_NTASK_Q in trcSnapshotConfig.h";
834 case TRACE_CLASS_TASK:
835 return "Not enough TASK handles - increase TRC_CFG_NTASK in trcSnapshotConfig.h";
836 case TRACE_CLASS_ISR:
837 return "Not enough ISR handles - increase TRC_CFG_NISR in trcSnapshotConfig.h";
838 default:
839 return "pszTraceGetErrorHandles: Invalid objectclass!";
840 }
841 }
842
843 /*******************************************************************************
844 * prvTraceIsSchedulerSuspended
845 *
846 * Returns true if the RTOS scheduler currently is disabled, thus preventing any
847 * task-switches from occurring. Only called from vTraceStoreISREnd.
848 ******************************************************************************/
849 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
prvTraceIsSchedulerSuspended(void)850 unsigned char prvTraceIsSchedulerSuspended(void)
851 {
852 return OSRunning != OS_STATE_OS_STOPPED;
853 }
854 #endif
855
856 #endif /* Snapshot mode */
857
858 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
859